OpenCV与图像处理学习八 | 您所在的位置:网站首页 › opencv 双阈值 › OpenCV与图像处理学习八 |
OpenCV与图像处理学习八——图像边缘提取(Canny检测代码)
一、图像梯度1.1 梯度1.2 图像梯度
二、梯度图与梯度算子2.1模板卷积2.2 梯度图2.3 梯度算子2.3.1 Roberts交叉算子2.3.2 Prewitt算子2.3.3 Sobel算子
三、Canny边缘检测算法(代码实现)
这次笔记简单介绍图像梯度、梯度图以及梯度算子的概念,并详细介绍三种基本的梯度算子,然后简单的介绍Canny检测的原理与代码实现(因为Canny检测中有很重要的一步用到了Sobel算子计算梯度,所以先介绍前面的内容)。 一、图像梯度 1.1 梯度先来看梯度的概念: 梯度是一个向量,梯度方向指向函数变化最快的方向,大小就是它的模,也是最大的变化率,对于二元函数z=f(x,y),它在点(x,y)的梯度记为: 图像梯度即图像中灰度变化的度量,求图像梯度的过程是二维离散函数求导过程。 因为图像边缘上的像素值变化非常剧烈,所以图像的边缘其实就是图像上灰度级变化很快的点的集合。 下图展示了一个灰度图的数学化表达,像素点(x,y)的灰度值是f(x,y),它有八个邻域(有时使用四邻域): 要理解梯度图的生成,就要先了解模板卷积的过程,模板卷积是模板运算的一种方式,其步骤如下: 将模板在输入图像中漫游,并将模板中心与图像中某个像素位置重合;将模板上各个系数与模板下各对应像素的灰度相乘;将所有乘积相加(为保持灰度范围,常将结果再除以模板系数之和,后面梯度算子模板和为0的话就不需要除了);将上述运算结果(模板的响应输出)赋给输出图像中对应模板中心位置的像素。
梯度图的生成和模板卷积相同,不同的是要生成梯度图,还需要在模板卷积完成后计算在点(x,y)梯度的幅值,将幅值作为像素值,这样才算完。 注意: 梯度图上每个像素点的灰度值就是梯度向量的幅度,生成梯度图需要两个模板(求图像梯度需要两个方向),右图为水平和竖直方向最简单的模板:
梯度算子是一阶导数算子,是水平G(x)和竖直G(y)方向对应模板的组合,也有对角线方向,即是上述卷积模板的组合。 常见的一阶算子:Roberts交叉算子, Prewitt算子, Sobel算子,下面将分别介绍。 2.3.1 Roberts交叉算子
因为Sobel算子的效果较好,实际使用中相比于另外两种更多,所以我们只看一下Sobel算子的例子。 函数: dst = cv2.Sobel( src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]] )参数: src:输入图像。 ddepth:输出图像位深度,-1表示采用的是与原图像相同的深度。目标图像的深度必须大于等于原图像的深度; dx:x导数的阶数,0表示这个方向上没有求导,一般为0、 1、 2; dy:y导数的阶数,0表示这个方向上没有求导,一般为0、 1、 2; ksize:Sobel算子的尺寸,必须是1,3,5或7。还可以是一个特殊值,ksize = FILTER_SCHARR (-1),那么将会使用scharr算子,在x方向的算子为: scale:(可选)计算的导数值的比例因子;默认情况下,不应用缩放。 delta:(可选)在将结果存储到dst中之前添加到结果中的增量值。 看个例子: import numpy as np import cv2 from matplotlib import pyplot as plt img = cv2.imread('./image/girl2.png', 0) sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=5) sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=5) plt.subplot(1, 3, 1), plt.imshow(img, cmap = 'gray') plt.title('Original'), plt.xticks([]), plt.yticks([]) plt.subplot(1, 3, 2), plt.imshow(sobelx, cmap = 'gray') plt.title('Sobel X'), plt.xticks([]), plt.yticks([]) plt.subplot(1, 3, 3),plt.imshow(sobely, cmap = 'gray') plt.title('Sobel Y'), plt.xticks([]), plt.yticks([]) plt.show()得到的就是该图像在x方向上和y方向上的梯度图: Canny算法是先平滑后求导数的方法。 John Canny研究了最优边缘检测方法所需的特性,给出了评价边缘检测性能优劣的三个指标: 好的信噪比,即将非边缘点判定为边缘点的概率要低,将边缘点判为非边缘点的概率要低;高的定位性能,即检测出的边缘点要尽可能在实际边缘的中心;对单一边缘仅有唯一响应,即单个边缘产生多个响应的概率要低,并且虚假响应边缘应该得到最大抑制。步骤: 彩色图像转换为灰度图像(以灰度图单通道图读入)对图像进行高斯模糊(去噪)计算图像梯度(这里用到了Sobel算子来计算图像梯度),根据梯度计算图像边缘幅值与角度沿梯度方向进行非极大值抑制(边缘细化)双阈值边缘连接处理二值化图像输出结果在OpenCV中的函数为: edges = cv2.Canny( image, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]] )参数: image:输入图像,灰度图。threshold1:双阈值边缘连接处理的第一个阈值。threshold2:双阈值边缘连接处理的第二个阈值。apertureSize:Sobel算子的尺寸。L2gradient:是否使用L2正则化更精确地计算梯度,还是使用L1。看个例子: # 加载 opencv 和 numpy import cv2 import numpy as np # 以灰度图形式读入图像 img = cv2.imread('./image/canny.png', 0) v1 = cv2.Canny(img, 80, 150, (3, 3)) v2 = cv2.Canny(img, 50, 100, (5, 5)) # np.vstack():在竖直方向上堆叠 # np.hstack():在水平方向上平铺堆叠 ret = np.hstack((v1, v2)) cv2.imshow('img', ret) cv2.waitKey(0) cv2.destroyAllWindows()原图如下所示: Canny检测作为传统的图像边缘提取算法,虽然效果上不如现在大火的深度学习的各种网络,但是对于一些边缘信息较为明显单一的图像来说任然有使用价值,我们将输入图像换一下: |
CopyRight 2018-2019 实验室设备网 版权所有 |